package com.cmccgz.udacs_landlord_webapp.utils;

import android.app.ProgressDialog;
import android.bluetooth.BluetoothAdapter;
import android.bluetooth.BluetoothDevice;
import android.bluetooth.BluetoothGatt;
import android.bluetooth.BluetoothGattCharacteristic;
import android.bluetooth.BluetoothGattService;
import android.bluetooth.BluetoothManager;
import android.content.BroadcastReceiver;
import android.content.ComponentName;
import android.content.Context;
import android.content.Intent;
import android.content.IntentFilter;
import android.content.ServiceConnection;
import android.content.pm.PackageManager;
import android.os.Handler;
import android.os.IBinder;
import android.os.Message;
import android.os.SystemClock;
import android.text.TextUtils;

import com.cmccgz.baselibrary.utils.ByteHexStringUtils;
import com.cmccgz.udacs_landlord_webapp.base.AppConfig;
import com.cmccgz.udacs_landlord_webapp.main.unlock.BluetoothLeNewService;
import com.orhanobut.logger.Logger;

import java.util.ArrayList;
import java.util.List;
import java.util.UUID;

import static android.content.Context.BIND_AUTO_CREATE;

/**
 * @author: Huang
 * @Descripion: 蓝牙解锁工具类
 * @date 2017/7/31 10:08
 */

public class BluetoothOpenDoorUtil {

    private static BluetoothOpenDoorUtil util;

    private static BluetoothOpenDoorUtil getInstance() {
        if (util == null) {
            util = new BluetoothOpenDoorUtil();
        }
        return util;
    }

    public static void clear() {
        if (util != null) {
            util.mContext = null;
            util = null;
        }
    }

    public static boolean checkBlueTooth(Context context) {
        BluetoothManager bluetoothManager =
                (BluetoothManager) context.getSystemService(Context.BLUETOOTH_SERVICE);
        BluetoothAdapter mBluetoothAdapter = bluetoothManager.getAdapter();
        return mBluetoothAdapter.isEnabled();
    }

    public static int checkBlueEnable(Context context) {
        if (!context.getPackageManager().hasSystemFeature(PackageManager.FEATURE_BLUETOOTH_LE)) {
            return STATE_BLUETOOTH_LE_FEATURE_UNABLE;
        } else if (((BluetoothManager) context.getSystemService(Context.BLUETOOTH_SERVICE)).getAdapter() == null) {
            return STATE_BLUETOOTH_UNABLE;
        } else {
            return STATE_BLUETOOTH_ENABLE;
        }
    }

    public static void unlockDoor(Context context, String deviceName, String sn, String password, openDoorCallback callback) {
        BluetoothOpenDoorUtil util = BluetoothOpenDoorUtil.getInstance();
        util.setParameters(context, deviceName, sn, password);
        util.setCallback(callback);
        util.open();
    }

    private BluetoothOpenDoorUtil() {
    }

    private void setParameters(Context context, String deviceName, String sn, String password) {
        this.mContext = context;
        this.deviceName = deviceName;
        this.sn = sn;
        this.password = password;
    }

    private void open() {
        mContext.registerReceiver(mGattUpdateReceiver, makeGattUpdateIntentFilter());
        BluetoothManager bluetoothManager =
                (BluetoothManager) mContext.getSystemService(Context.BLUETOOTH_SERVICE);
        adapter = bluetoothManager.getAdapter();
        if (adapter.isEnabled()) {
            bindService(mContext);
        } else {
            error("请开启蓝牙！");
        }
    }

    private BluetoothAdapter adapter;
    private openDoorCallback mCallback;
    private BluetoothDevice currentBluetoothDevice = null;
    private Context mContext;
    private String deviceName;
    private String sn;
    private String password;
    private ProgressDialog progressDialog;
    public static final int STATE_BLUETOOTH_LE_FEATURE_UNABLE = 0;
    public static final int STATE_BLUETOOTH_ENABLE = 1;
    public static final int STATE_BLUETOOTH_UNABLE = 2;
    public static final int REQUEST_ENABLE_BT = 1;
    private boolean isBound = false;
    private BluetoothLeNewService mBluetoothLeNewService;
    private String result_code = "";
    private String msg_code = "";
    private List<String> addresses = new ArrayList<>();
    private static final long SCAN_PERIOD = 5000;
    private static final long UNLOCK_PERIOD = 15000;
    private ServiceConnection connection = new ServiceConnection() {
        @Override
        public void onServiceConnected(ComponentName name, IBinder service) {
            Logger.e("服务连接成功！");
            mBluetoothLeNewService = ((BluetoothLeNewService.LocalBinder) service).getService();
            if (!mBluetoothLeNewService.initialize()) {
                Logger.e("Unable to initialize Bluetooth");
            }
            scanLeDevice(true);
        }

        @Override
        public void onServiceDisconnected(ComponentName name) {
            Logger.e("断开服务链接！");
            scanLeDevice(false);
            mBluetoothLeNewService = null;
        }
    };
    private Handler mHandler = new Handler() {
        @Override
        public void handleMessage(Message msg) {
            switch (msg.what) {
                case 0:
                    scanLeDevice(false);
                    currentBluetoothDevice = (BluetoothDevice) msg.obj;
                    addresses.add(currentBluetoothDevice.getAddress());
                    mHandler.postDelayed(unlockStopRunnable, UNLOCK_PERIOD);
                    showUnCancelLoadingDialog("正在连接设备...");
                    boolean isConnect = mBluetoothLeNewService.connect(currentBluetoothDevice);
                    if (!isConnect) {
                        error("连接设备异常!");
                    }
                    break;
            }
        }
    };

    private void scanLeDevice(boolean isScan) {
        if (isScan) {
            mHandler.postDelayed(stopRunnable, SCAN_PERIOD);
            adapter.startLeScan(new UUID[]{UUID.fromString(AppConfig.UUID_SERVICE)}, mLeScanCallback);
//            adapter.startLeScan(mLeScanCallback);
            showUnCancelLoadingDialog("正在扫描门禁...");
        } else {
            mHandler.removeCallbacks(stopRunnable);
            adapter.stopLeScan(mLeScanCallback);
        }
    }

    private Runnable stopRunnable = new Runnable() {
        @Override
        public void run() {
            adapter.stopLeScan(mLeScanCallback);
            if (addresses.size() == 0) {
                error("没有搜索到设备！");
            }
        }
    };

    private BluetoothAdapter.LeScanCallback mLeScanCallback = new BluetoothAdapter.LeScanCallback() {
        @Override
        public void onLeScan(BluetoothDevice device, int rssi, byte[] scanRecord) {
            Logger.e("name:" + device.getName() + "address:" + device.getAddress());
            if ((!TextUtils.isEmpty(device.getName())) && (rssi >= -95) && (!addresses.contains(device.getAddress()))) {
                if (deviceName.equals(device.getName())) {
                    Message message = Message.obtain();
                    message.what = 0;
                    message.obj = device;
                    mHandler.sendMessage(message);
                }
            }
        }
    };

    private Runnable unlockStopRunnable = new Runnable() {
        @Override
        public void run() {
            error("设备无响应，请重试!");
        }
    };

    private BroadcastReceiver mGattUpdateReceiver = new BroadcastReceiver() {
        @Override
        public void onReceive(Context context, Intent intent) {
            final String action = intent.getAction();
            switch (action) {
                case BluetoothLeNewService.ACTION_GATT_CONNECTED:
                    break;
                case BluetoothLeNewService.ACTION_GATT_DISCONNECTED:
                    error("设备连接异常！");
                    break;
                case BluetoothLeNewService.ACTION_GATT_DESCRIPTOR_WRITE_SUCCESS:
                    Logger.e("收到descriptor写入成功广播");
                    writeCode();
                    break;
                case BluetoothLeNewService.ACTION_GATT_DESCRIPTOR_WRITE_FAILED:
                    error("descriptor写入失败！");
                    break;
                case BluetoothLeNewService.ACTION_GATT_SERVICES_DISCOVERED_FAILED:
                    error("服务发现失败！");
                    break;
                case BluetoothLeNewService.ACTION_GATT_CHARACTERISTIC_WRITE_FAILED:
                    error("数据写入失败！");
                    break;
                case BluetoothLeNewService.ACTION_DATA_AVAILABLE:
                    displayData(intent);
                    break;
                default:
                    break;
            }
        }
    };

    private void error(String msg) {
        finish();
        dismissLoadingDialog();
        if (mCallback != null) {
            mCallback.onFailed(msg);
        }
    }

    private void success() {
        finish();
        dismissLoadingDialog();
        if (mCallback != null) {
            mCallback.onSuccess();
        }
    }

    private void finish() {
        scanLeDevice(false);
        mHandler.removeCallbacks(unlockStopRunnable);
        if (mBluetoothLeNewService != null) {
            mBluetoothLeNewService.disconnect();
        }
        unbindService(mContext);
        mContext.unregisterReceiver(mGattUpdateReceiver);
        addresses.clear();
        currentBluetoothDevice = null;
    }

    private void showUnCancelLoadingDialog(String message) {
        try {
            if (progressDialog != null && progressDialog.isShowing()) {
                progressDialog.setMessage(message);
                progressDialog.show();
            } else {
                progressDialog = ProgressDialog.show(mContext, "", message, false, false);
                progressDialog.show();
            }
        } catch (Exception e) {
            Logger.e(e.getMessage());
        }
    }

    private void dismissLoadingDialog() {
        try {
            if (progressDialog != null && progressDialog.isShowing()) {
                progressDialog.dismiss();
                progressDialog = null;
            }
        } catch (Exception e) {
            Logger.e(e.getMessage());
        }
    }


    private void bindService(Context context) {
        Intent gattServiceIntent = new Intent(context, BluetoothLeNewService.class);
        isBound = context.bindService(gattServiceIntent, connection, BIND_AUTO_CREATE);
    }

    private void unbindService(Context context) {
        if (isBound && connection != null) {
            context.unbindService(connection);
            isBound = false;
        }
    }

    private void setCallback(openDoorCallback callback) {
        this.mCallback = callback;
    }

    public interface openDoorCallback {
        void onSuccess();

        void onFailed(String msg);
    }

    private IntentFilter makeGattUpdateIntentFilter() {
        final IntentFilter intentFilter = new IntentFilter();
        intentFilter.addAction(BluetoothLeNewService.ACTION_GATT_CONNECTED);
        intentFilter.addAction(BluetoothLeNewService.ACTION_GATT_DISCONNECTED);
        intentFilter.addAction(BluetoothLeNewService.ACTION_GATT_SERVICES_DISCOVERED_FAILED);
        intentFilter.addAction(BluetoothLeNewService.ACTION_GATT_DESCRIPTOR_WRITE_SUCCESS);
        intentFilter.addAction(BluetoothLeNewService.ACTION_GATT_DESCRIPTOR_WRITE_FAILED);
        intentFilter.addAction(BluetoothLeNewService.ACTION_GATT_CHARACTERISTIC_WRITE_FAILED);
        intentFilter.addAction(BluetoothLeNewService.ACTION_DATA_AVAILABLE);
        intentFilter.addAction(BluetoothLeNewService.ACTION_STATE_ON);
        intentFilter.addAction(BluetoothLeNewService.ACTION_STATE_OFF);
        return intentFilter;
    }

    private void writeCode() {
        if (currentBluetoothDevice != null) {
            showUnCancelLoadingDialog("正在解锁...");
            SystemClock.sleep(15);
            doUnlock();
        }
    }

    private void doUnlock() {
        String unlockCode = getUnlockCode();
        Logger.e("解锁码：" + unlockCode);
        BluetoothGatt gatt = mBluetoothLeNewService.getBluetoothGatt();
        BluetoothGattService service = gatt.getService(UUID.fromString(AppConfig.UUID_SERVICE));
        if (service == null) {
//                mUnlockView.dismissUnlockDialog("设备异常，请稍后再试！");
            error("无服务");
            return;
        }
        BluetoothGattCharacteristic characteristic = service.getCharacteristic(UUID.fromString(AppConfig.UUID_CHARACTERISTIC));
        if (characteristic == null) {
//                mUnlockView.dismissUnlockDialog("设备异常，请稍后再试！");
            error("无characteristic");
            return;
        }
        int properties = characteristic.getProperties();
        if ((properties | BluetoothGattCharacteristic.PROPERTY_NOTIFY) > 0) {

            // 7E                                 头
            // 46432D38393130413137303430313032   设备sn码
            // FFFFFFFF                           设备密码
            // 1F86B5C3                           信息代码
            // 030300                             控制码
            // 00000004                           数据码
            // 01000000                           数据内容
            // 7C                                 检验码
            // 7E                                 尾
//                String hexString = "7E46432D38393130413137303430313032FFFFFFFF1F86B5C303030000000004010000007C7E";

            byte[] bytes = ByteHexStringUtils.hexStringToBytes(unlockCode);
            int count;
            int num = bytes.length % 20;
            if (num > 0) {
                count = bytes.length / 20 + 1;
            } else {
                count = bytes.length / 20;
            }
            for (int i = 0; i < count; i++) {
                byte[] packageByte;
                if (i == count - 1) {
                    packageByte = new byte[num];
                    System.arraycopy(bytes, i * 20, packageByte, 0, num);
                } else {
                    packageByte = new byte[20];
                    System.arraycopy(bytes, i * 20, packageByte, 0, 20);
                }
                characteristic.setValue(packageByte);
                mBluetoothLeNewService.writeCharacteristic(characteristic);
                SystemClock.sleep(13);
            }
        }
    }

    private String getUnlockCode() {
        result_code = "";
        msg_code = ByteHexStringUtils.randomHexString(8);
        String dataString = sn + password + msg_code + AppConfig.CODE_OPEN_CONTROL +
                AppConfig.CODE_OPEN_DETA_KEY + AppConfig.CODE_OPEN_DETA;
        byte[] dataBytes = ByteHexStringUtils.hexStringToBytes(dataString);
        byte[] sumCheck = ByteHexStringUtils.SumCheck(dataBytes, 1);
        String checkSum = ByteHexStringUtils.bytesToHexString(sumCheck);
        dataString += checkSum;
        String translationCode = ByteHexStringUtils.translation(dataString);
        return AppConfig.CODE_BASE + translationCode + AppConfig.CODE_BASE;
    }

    private void displayData(Intent intent) {
        String data = intent.getStringExtra(BluetoothLeNewService.EXTRA_DATA);
        Logger.e("收到消息：" + data);
        if (!TextUtils.isEmpty(data)) {
            String upperCase = data.toUpperCase();
            result_code += upperCase;
            if (upperCase.endsWith(AppConfig.CODE_BASE)) {
                Logger.e("解锁响应码：" + result_code);
                resultReceiveComplete();
            }
        }
    }

    private void resultReceiveComplete() {
        String substring = result_code.substring(2, result_code.length() - 2);
        String[] split = substring.split("7E7E");
        for (String code : split) {
            String reverseTranslation = ByteHexStringUtils.reverseTranslation(code);
            Logger.e("转译后的指令:" + reverseTranslation);
            if (reverseTranslation.length() == 64) {
                String checkCode = reverseTranslation.substring(62, 64);
                String dataCode = reverseTranslation.substring(0, 62);
                byte[] dataBytes = ByteHexStringUtils.hexStringToBytes(dataCode);
                byte[] sumCheck = ByteHexStringUtils.SumCheck(dataBytes, 1);
                String checkSum = ByteHexStringUtils.bytesToHexString(sumCheck);
                if (!checkCode.equals(checkSum != null ? checkSum.toUpperCase() : null)) {
//                    mUnlockView.dismissUnlockDialog("设备异常，请稍后再试！");
                    error("校验和错误");
                    return;
                }
                String resultMsgCode = reverseTranslation.substring(0, 8);
                String resultSn = reverseTranslation.substring(8, 40);
                String resultPsd = reverseTranslation.substring(40, 48);
                if (resultMsgCode.equals(msg_code) && resultSn.equals(sn) && resultPsd.equals(password)) {
                    String controlCode = reverseTranslation.substring(48, 54);
                    if (AppConfig.CODE_OPEN_RESULT_OK_OCNTROL.equals(controlCode)) {
                        success();
                    } else {
                        error("解锁失败！");
                    }
                } else {
//                    mUnlockView.dismissUnlockDialog("设备异常，请稍后再试！");
                    error("设备信息或信息代码错误");
                }
            } else if (reverseTranslation.length() == 80) {

            } else {
                error("返回数据长度有误");
            }
        }
        result_code = "";
    }

    //    private BluetoothAdapter checkBluetooth() {
//        if (!mContext.getPackageManager().hasSystemFeature(PackageManager.FEATURE_BLUETOOTH_LE)) {
//            error(mContext.getString(R.string.ble_not_supported));
//            return null;
//        }
//        final BluetoothManager bluetoothManager =
//                (BluetoothManager) mContext.getSystemService(Context.BLUETOOTH_SERVICE);
//        BluetoothAdapter mBluetoothAdapter = bluetoothManager.getAdapter();
//        if (mBluetoothAdapter == null) {
//            error(mContext.getString(R.string.error_bluetooth_not_supported));
//            return null;
//        } else if (!mBluetoothAdapter.isEnabled()) {
//            Logger.e("初始化蓝牙");
//            Intent intent = new Intent(BluetoothAdapter.ACTION_REQUEST_ENABLE);
//            ((HostActivity) mContext).startActivityForResult(intent, REQUEST_ENABLE_BT);
//            return mBluetoothAdapter;
//        } else {
//            bindService(mContext);
//            return mBluetoothAdapter;
//        }
//    }
}
